// 引入其他的类
import Snake from './Snake'
import Food from './Food'
import ScorePanel from './ScorePanel'

// 游戏控制器，控制其他的所有类
class GameControl {
  // 定义三个属性 蛇 食物 记分牌
  snake: Snake
  food: Food
  scorePanel: ScorePanel

  // 创建一个属性来存储蛇的移动方向（也就是按键方向）
  direction: string = ''

  // 创建一个属性用来记录游戏是否结束
  isLive = true

  constructor() {
    this.snake = new Snake()
    this.food = new Food()
    this.scorePanel = new ScorePanel(10, 4) // 最高等级 升级分数

    this.init()
  }

  // 游戏的初始化方法，调用后游戏即开始
  init() {
    // 绑定键盘按键按下的事件
    // document 调用了 keydownHandler ，那 keydownHandler 中的 this 就是 document
    // .bind(this) 把当前的 this 绑定上去，
    // 则 keydownHandler 中的 this 就不会管调用者了，而是当前的 this
    document.addEventListener('keydown', this.keydownHandler.bind(this))

    // 调用 run 方法，使蛇移动
    this.run()
  }

  // 创建一个键盘按下的响应函数
  /**
   * Chrome中
   * ArrowUp
   * ArrowDown
   * ArrowLeft
   * ArrowRight
   * IE中
   * Up
   * Down
   * Left
   * Right
   */
  keydownHandler(event: KeyboardEvent) {
    // 修改 direction 属性
    // 需要检查 event.key 的值是否合法（用户是否按了正确的按键）
    this.direction = event.key
  }

  // 创建一个控制蛇移动的方法
  run() {
    //  根据方向（this.direction）来使蛇的位置改变
    // 获取蛇现在的坐标
    let X = this.snake.X
    let Y = this.snake.Y 

    // 根据按键的方向，来修改 X 和 Y
    switch (this.direction) {
      case "ArrowUp":
      case "Up":
        // 向上 top -= 10
        // Y -= 10
        Y = this.snake.amendY(Y - 10)
        break
      case "ArrowDown":
      case "DOwn":
        // 向下 top += 10
        // Y += 10
        Y = this.snake.amendY(Y + 10)
        break
      case "ArrowLeft":
      case "Left":
        // 向左 left -= 10
        // X -= 10
        X = this.snake.amendX(X - 10)
        break
      case "ArrowRight":
      case "Right":
        // 向右 left += 10
        // X += 10
        X = this.snake.amendX(X + 10)
        break
    }

    
    // 检查蛇是否吃到食物，进行相应操作
    this.checkEat(X, Y)

    // 修改蛇的 X 和 Y
    try {
      this.snake.X = X
      this.snake.Y = Y
    } catch (e) {
      // 出现异常，游戏结束
      alert(e.message + '\nGAME OVER!')
      this.isLive = false
    }


    // 开启一个定时调用 - 每隔 300 就 run 一下
    // 根据 level 限定速度
    let speed = 300 - (this.scorePanel.level - 1) * 25
    // 活着才 run
    this.isLive && setTimeout(this.run.bind(this), speed)
  }

  // 定义一个方法，用来检查蛇是否吃到食物
  checkEat(X: number, Y: number) {
    if (X === this.food.X && Y === this.food.Y) {      
      // 吃到食物后
      // 蛇增加一节
      this.snake.addBody()
      // 食物的位置要进行重置
      this.food.change()
      // 分数增加
      this.scorePanel.addScore()
    }
  }


}

export default GameControl
